/*****************************************************************************

FileName: <decodeBMP.cpp>

Description:
Sample Application showing how to use bmpdecode library

*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>

#include <codec.h>
#include <common.h>
#include <error.h>
#include <types.h>

#include <dbmp.h>
#include <vidout.h>


#ifdef WINDOWS
#pragma comment (lib, "../../../lib/win/vidout.lib")
#pragma comment (lib, "../../../lib/win/dbmp.lib")
#endif


/* Function Prototypes */
void GetBuffer();
void custom_display_event(void);
void custom_key_event(unsigned char key, int x, int y);
void custom_specialkey_event(int key, int x, int y);
void custom_animate_event(void);
void custom_reshape_event(int w, int h);


/* Global Variables */
DisplayDevice *pDisplayDevice;


/*****************************************************************************
Routine:  int main(int argc, char *argv[])

returns        	: int
Description     : Main Function
*****************************************************************************/
int main(int argc, char *argv[])
{

	FILE *pInFile;
	char *pInFileName;
	int nSizeOfBuffer;

	ErrorType eError;
	CodecHandle hCodec;
	BitmapdInMetaData *pInMetaData;
	BitmapdOutMetaData *pOutMetaData;


	pInFileName = argv[1];
	pInFile = fopen(pInFileName, "rb");
	if(!pInFile) exit(-1);


	/* Init Codec Instance and Data structures */
	hCodec 			= (CodecInstance *)malloc(sizeof(CodecInstance));
	pInMetaData 	= (BitmapdInMetaData *)malloc(sizeof(BitmapdInMetaData));
	pOutMetaData 	= (BitmapdOutMetaData *)malloc(sizeof(BitmapdOutMetaData));

	memset(hCodec, 0x0, sizeof(CodecInstance));
	memset(pInMetaData, 0x0, sizeof(BitmapdInMetaData));
	memset(pOutMetaData, 0x0, sizeof(BitmapdOutMetaData));


	/* Map Codec Functions to the Codec Instance Function Pointers */
	hCodec->pInitCodec = InitBitmapDecode;
	hCodec->pProcess = BitmapDecode;


	/* Init Codec Resources */
	pInMetaData->pFile = pInFile;
	eError = hCodec->pInitCodec(hCodec, pInMetaData, pOutMetaData);

	/* Allocate Memory For the Buffers */
	nSizeOfBuffer = pOutMetaData->nWidth * pOutMetaData->nHeight * 3;
	pOutMetaData->pBuffer = (UINT8*)malloc(sizeof(UINT8)*nSizeOfBuffer);

	/* Call Decode Function */
	eError = hCodec->pProcess(hCodec, pInMetaData, pOutMetaData);

	/* Configure Display Device */
	pDisplayDevice = (DisplayDevice *)malloc(sizeof(DisplayDevice));
	memset(pDisplayDevice, 0x0, sizeof(DisplayDevice));
	pDisplayDevice->pInBuffer 	 = pOutMetaData->pBuffer;
	pDisplayDevice->nFrameWidth  = pOutMetaData->nWidth;
	pDisplayDevice->nFrameHeight = pOutMetaData->nHeight;
	pDisplayDevice->nInFmt 	 	 = 29;	// Output is in BGRpacked fmt
	pDisplayDevice->nRunning 	 = 1;
	pDisplayDevice->nFrameRate 	 = 10;
	pDisplayDevice->nFrameNum 	 = 0;
	pDisplayDevice->nTime 		 = 0;


	/* Create Window */
	glutInitWindowSize(pDisplayDevice->nFrameWidth, pDisplayDevice->nFrameHeight);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE);
	(void)glutCreateWindow("GraphicsDevPkg");


	/* Initialize Display Device */
	DisplayDevInit(pDisplayDevice);


	/* Map GLUT callback functions */
	glutDisplayFunc(custom_display_event);
	glutKeyboardFunc(custom_key_event);
	glutSpecialFunc(custom_specialkey_event);
	glutReshapeFunc(custom_reshape_event);
	glutIdleFunc(custom_animate_event);

	/* Run Callback Loop */
	glutMainLoop();


	return 0;

}




/*****************************************************************************
Routine:  void GetBuffer()

returns        	: void
Description     : Generates New Buffer For Display
*****************************************************************************/
void GetBuffer()
{	

	/* NULL For Graphics Formats */
	/* The frame to be displayed is already obtained */

}



/*****************************************************************************
Routine:  void custom_display_event()

returns        	: void
Description     : CallBack function for display
*****************************************************************************/
void custom_display_event(void) 
{

	glClear(GL_COLOR_BUFFER_BIT);
	glBindTexture(GL_TEXTURE_2D, textureid);
	glPushMatrix();
	glBegin(GL_POLYGON);

	// left top
	glTexCoord2f(0.0, (1-pDisplayDevice->nRelHeight));
	glVertex2f(-1.0, -1.0);

	// right top
	glTexCoord2f(pDisplayDevice->nRelWidth, (1-pDisplayDevice->nRelHeight));
	glVertex2f(1.0, -1.0);

	// right bottom
	glTexCoord2f(pDisplayDevice->nRelWidth, 1.0);
	glVertex2f(1.0, 1.0);

	// left bottom
	glTexCoord2f(0.0, 1.0);
	glVertex2f(-1.0, 1.0);

	glEnd();
	glPopMatrix();
	glutSwapBuffers();
	glBindTexture(GL_TEXTURE_2D, 0);

}


/*****************************************************************************
Routine:  void custom_key_event(unsigned char key, int x, int y)

returns        	: void
Description     : CallBack function for KeyHit
*****************************************************************************/
void custom_key_event(unsigned char key, int x, int y)
{
	switch(key) 
	{
	case '\033'	: exit(0); break;
	case ' '	: break;
	default		: break;
	}
	glutPostRedisplay();
}



/*****************************************************************************
Routine:  void custom_specialkey_event(int key, int x, int y)

returns        	: void
Description     : CallBack function for KeyHit
*****************************************************************************/
void custom_specialkey_event(int key, int x, int y)
{
	switch(key) 
	{
	case GLUT_KEY_PAGE_UP	:				break;
	case GLUT_KEY_PAGE_DOWN :				break;
	case GLUT_KEY_RIGHT		:				break;
	case GLUT_KEY_LEFT		:				break;
	case GLUT_KEY_HOME		:				break;
	default:								break;
	}

}



/*****************************************************************************
Routine:  void custom_animate_event()

returns        	: void
Description    	: Animation
*****************************************************************************/
void custom_animate_event(void) 
{

	pDisplayDevice->nTime = 1000*((double)pDisplayDevice->nFrameNum)/pDisplayDevice->nFrameRate;
	if(pDisplayDevice->nTime <= glutGet(GLUT_ELAPSED_TIME))
	{
		if(pDisplayDevice->nRunning)
		{
			GetBuffer();
			DisplayFrame(pDisplayDevice);

			if(pDisplayDevice->nRunning==1)					// If graphics mode
				pDisplayDevice->nRunning = 0;				// Stop running after first frame
		}
		pDisplayDevice->nFrameNum ++;
	}

	glutPostRedisplay();
}



/*****************************************************************************
Routine:  custom_reshape_event(int w, int h)

returns        	: void
Description    	: CallBack function for Reshape
*****************************************************************************/
void custom_reshape_event(int w, int h) 
{
	glViewport(0, 0, w, h);
}



